/**
 * 禁查词接口
 */
import {
    directus,
    getItems,
    getItemById,
    createItem,
    updateItem,
    deleteItem,
} from "../directus";

/** 集合名 */
export const COLLECTION_FORBIDDEN = "forbidden_queries" as const;

/** 状态 */
export type ForbiddenStatus = "published" | "draft" | "archived";

/** 列表项 / 详情项 */
export interface ForbiddenItem {
    id: number | string;
    query?: string;
    status?: ForbiddenStatus;
    date_created?: string;
}

/** 列表查询参数 */
export interface ForbiddenListParams {
    page?: number;
    pageSize?: number;
    keyword?: string;
    sort?: string | string[];
    excludeStatus?: ForbiddenStatus | null;
    signal?: AbortSignal;
}

/** 列表返回结果 */
export interface ForbiddenListResult {
    list: ForbiddenItem[];
    total: number;
}

/** 导出参数 */
export interface ExportForbiddenParams {
    ids?: Array<number | string>;
    keyword?: string;
    excludeStatus?: ForbiddenStatus | null;
    sort?: string | string[];
    format?: "csv" | "json";
    signal?: AbortSignal;
}

/* ------------------------- 公共常量 & 工具函数 ------------------------- */

const FIELDS_BASE = ["id", "query", "status", "date_created"] as const;
type FieldKey = (typeof FIELDS_BASE)[number];

const normalizeSort = (sort?: string | string[]) =>
    Array.isArray(sort) ? sort.filter(Boolean) : sort ? [sort] : [];

const safeTrim = (s?: string) => (typeof s === "string" ? s.trim() : "");

const buildFilter = ({
    excludeStatus,
    keyword,
    ids,
}: {
    excludeStatus?: ForbiddenStatus | null;
    keyword?: string;
    ids?: Array<number | string>;
}) => {
    const filter: Record<string, any> = {};
    if (excludeStatus) filter.status = { _neq: excludeStatus };
    const kw = safeTrim(keyword);
    if (kw) filter._or = [{ query: { _icontains: kw } }];
    if (ids && ids.length) filter.id = { _in: ids };
    return filter;
};

const dateStamp = () => {
    const d = new Date();
    const p = (n: number) => String(n).padStart(2, "0");
    return `${d.getFullYear()}${p(d.getMonth() + 1)}${p(d.getDate())}_${p(
        d.getHours()
    )}${p(d.getMinutes())}${p(d.getSeconds())}`;
};

const toCsv = (rows: Array<Record<string, any>>, header: string[]) => {
    const esc = (v: any) => {
        const s = String(v ?? "");
        return /[",\n]/.test(s) ? `"${s.replace(/"/g, '""')}"` : s;
    };
    const lines = [header, ...rows.map((r) => header.map((h) => r[h]))]
        .map((arr) => arr.map(esc).join(","))
        .join("\n");
    // 加 BOM，Excel 友好
    return "\uFEFF" + lines;
};

/* ===================== 获取列表 ===================== */

/** 获取禁查词分页列表 */
export async function getForbiddenList(
    params: ForbiddenListParams = {}
): Promise<ForbiddenListResult> {
    const {
        page = 1,
        pageSize = 25,
        keyword = "",
        sort = ["-id"],
        excludeStatus = "archived",
        signal,
    } = params;

    const res: any = await getItems<ForbiddenItem>(COLLECTION_FORBIDDEN, {
        page,
        limit: pageSize,
        fields: FIELDS_BASE as unknown as FieldKey[],
        sort: normalizeSort(sort),
        filter: buildFilter({ excludeStatus, keyword }),
        meta: "filter_count",
        signal,
    });

    const list: ForbiddenItem[] = res?.data ?? res ?? [];
    const total: number =
        res?.meta?.filter_count ?? res?.meta?.total_count ?? list.length;
    return { list, total };
}

/* ===================== 新增 / 更新 / 详情 ===================== */

/** 新增 */
export function createForbidden(payload: {
    query: string;
    status?: ForbiddenStatus;
}) {
    return createItem<ForbiddenItem>(COLLECTION_FORBIDDEN, payload);
}

/** 更新 */
export function updateForbidden(
    id: number | string,
    payload: Partial<ForbiddenItem>
) {
    return updateItem<ForbiddenItem>(COLLECTION_FORBIDDEN, id, payload);
}

/** 详情 */
export function getForbiddenById(id: number | string) {
    return getItemById<ForbiddenItem>(COLLECTION_FORBIDDEN, id, [
        "id",
        "query",
        "status",
        "date_created",
    ]);
}

/* ===================== 删除 / 批量删除 ===================== */

/** 删除（单个） */
export function deleteForbidden(id: number | string) {
    return deleteItem(COLLECTION_FORBIDDEN, id);
}

/** 批量删除 */
export async function deleteForbiddens(ids: Array<number | string>) {
    if (!ids?.length) return;
    try {
        await directus.delete(`/items/${COLLECTION_FORBIDDEN}`, {
            headers: { "Content-Type": "application/json" },
            data: { keys: ids },
        });
    } catch {
        await Promise.all(ids.map((id) => deleteForbidden(id)));
    }
}

/* ===================== 启用 / 停用 ===================== */

/** 启用 => published */
export function enableForbidden(id: number | string) {
    return updateForbidden(id, { status: "published" });
}

/** 停用 => draft */
export function disableForbidden(id: number | string) {
    return updateForbidden(id, { status: "draft" });
}

/* ===================== 当前用户 ID ===================== */

export async function getCurrentUserId(
    signal?: AbortSignal
): Promise<string | number | undefined> {
    const res: any = await directus.get("/users/me", {
        params: { fields: "id" },
        signal: signal as any,
    });
    const data = res?.data;
    return (data && (data.data?.id ?? data.id)) as any;
}

/* ===================== 导入 ===================== */

const IMPORT_FORBIDDEN_ENDPOINT = "/utils/import/forbidden_queries";

export interface ImportForbiddenOpts {
    filename?: string;
    extra?: Record<string, string | number | boolean>;
    signal?: AbortSignal;
}

/** 导入 */
export async function importForbiddens(
    file: Blob | File,
    opts: ImportForbiddenOpts = {}
): Promise<any> {
    if (!file) throw new Error("请先选择要导入的文件");

    const fd = new FormData();
    const filename =
        opts.filename || (file instanceof File ? file.name : "forbidden.csv");
    fd.append("file", file, filename);

    if (opts.extra) {
        Object.entries(opts.extra).forEach(([k, v]) => fd.append(k, String(v)));
    }

    const res = await directus.post(IMPORT_FORBIDDEN_ENDPOINT, fd, {
        signal: opts.signal as any,
    });
    return (res as any)?.data ?? {};
}

/* ===================== 导出（CSV / JSON） ===================== */
export async function exportForbiddens(params: ExportForbiddenParams = {}) {
    const {
        ids,
        keyword = "",
        excludeStatus = "archived",
        sort = ["-id"],
        format = "csv",
        signal,
    } = params;

    const filter = buildFilter({ excludeStatus, keyword, ids });

    const limit = 500;
    let page = 1;
    const all: ForbiddenItem[] = [];

    while (true) {
        const res: any = await getItems<ForbiddenItem>(COLLECTION_FORBIDDEN, {
            page,
            limit,
            fields: FIELDS_BASE as unknown as FieldKey[],
            sort: normalizeSort(sort),
            filter,
            signal,
        });
        const chunk: ForbiddenItem[] = res?.data ?? res ?? [];
        all.push(...chunk);
        if (!chunk.length || chunk.length < limit) break;
        page += 1;
    }

    const rows = all.map((x) => ({
        id: x.id,
        query: x.query ?? "",
        status: x.status ?? "draft",
        date_created: x.date_created ?? "",
    }));

    const stamp = dateStamp();

    if (format === "json") {
        const blob = new Blob([JSON.stringify(rows, null, 2)], {
            type: "application/json;charset=utf-8",
        });
        return {
            blob,
            filename: `forbidden_${stamp}_${rows.length}.json`,
            count: rows.length,
        };
    }

    const header = ["id", "query", "status", "date_created"];
    const csv = toCsv(rows as any[], header);
    const blob = new Blob([csv], { type: "text/csv;charset=utf-8" });
    return {
        blob,
        filename: `forbidden_${stamp}_${rows.length}.csv`,
        count: rows.length,
    };
}
